package com.tajlip;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.SortDirection;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Abstracts the Java code required to edit entries already in Google's database.
 * This ideall should support all the CRUD actions: create, read, update, and
 * delete. Create and delete are covered... :-p
 */
public class EditFilter implements Filter {

    private FilterConfig filterConfig = null;

    /**
     * Deletes any entries that the user requested. This method uses the logical
     * 'id' that the comic website uses, maps it to Google's unique Key, and
     * requests that Google deletes all Entity objects associated with the Key(s).
     */
    public void doDeleteRequests(HttpServletRequest req, DatastoreService dataService) throws NumberFormatException {
        // make a list of comics to delete
        Set<Integer> comicsToDelete = new HashSet();
        String[] values = req.getParameterValues("d");
        if (values != null) {
            for (String value : values) {
                comicsToDelete.add(Integer.parseInt(value));
            }
        }
        // delete if anything needs it
        if (!comicsToDelete.isEmpty()) {
            Set<Key> keysToDelete = new HashSet();
            // query all the comies from BigTable
            Query query = new Query(Comic.KIND);
            PreparedQuery preparedQuery = dataService.prepare(query);
            for (Entity entity : preparedQuery.asIterable()) {
                Long id = (Long) entity.getProperty("id");
                if (comicsToDelete.contains(id.intValue())) {
                    keysToDelete.add(entity.getKey());
                }
            }
            // delete all by key
            dataService.delete(keysToDelete);
        }
    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;

        DatastoreService dataService = DatastoreServiceFactory.getDatastoreService();

        // do any delete requests
        doDeleteRequests(req, dataService);

        // do any edit/update requests
        // meh -- we never make mistakes!

        // set in request scope a list of all of the comics
        ArrayList<Comic> comics = new ArrayList();
        // query all the comies from BigTable
        Query query = new Query(Comic.KIND);
        query.addSort("timestamp", SortDirection.DESCENDING);
        PreparedQuery preparedQuery = dataService.prepare(query);
        for (Entity result : preparedQuery.asIterable()) {
            // make the comic but omit the binary image data -- we don't need it
            Comic comic = new Comic();
            comic.id = ((Long) result.getProperty("id")).intValue();
            comic.title = (String) result.getProperty("title");
            comic.description = (String) result.getProperty("description");
            comic.tags = (String) result.getProperty("tags");
            comic.timestamp = (Long) result.getProperty("timestamp");
            // ignore the binary data -- we're not using it here
//            comic.image = (Blob) result.getProperty("image");
//            comic.imageSmall = (Blob) result.getProperty("image-small");
            comics.add(comic);
        }

        // put in request scope
        request.setAttribute("comics", comics);

        // always send to filter-test.jsp
        req.getRequestDispatcher("/edit.jsp").forward(req, res);
    }

    public void destroy() {
    }

    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
    }
}